module FlsParser where

import Control.Applicative
import Data.Maybe (fromJust)
import Data.ByteString as B
import qualified Data.ByteString.Char8 as BC
import Data.Attoparsec.Lazy
import qualified Data.Attoparsec.Char8 as A
import qualified Data.ByteString.Lazy.Char8 as L

data BodyLine = BL {
     md5 :: Integer,
     fn  :: B.ByteString,
     inode :: Inode,
     fileType :: FileType,
     filePerms  :: FilePerms,
     uid :: Integer,
     gid :: Integer,
     size :: Integer,
     atime :: Integer,
     mtime :: Integer,
     ctime :: Integer,
     crtime :: Integer
} | EmptyBLine deriving (Show)

data Inode = Inode { --need to rename attr-type attr-id
     entryNum :: Integer,
     dataAttr :: Integer,
     dataSub :: Integer
} | EmptyInode B.ByteString deriving (Show)

data FileType = FT {
     fnStruct :: Char,
     metaStruct :: Char
} | EmptyFileType deriving (Show)

data Perms = P {
     read :: Bool,
     write :: Bool,
     exec :: Bool
} |EmptyPerms deriving (Show)

data FilePerms = FP {
     owner :: Perms,
     group :: Perms,
     other :: Perms
} | EmptyFilePerms deriving (Show)

data Event = E {
     e_fn :: B.ByteString,
     e_atime :: Integer,
     e_mtime :: Integer,
     e_ctime :: Integer,
     e_crtime :: Integer
} deriving (Show)

foundBar w = w == 124

bar = 124

hyphen = 45

slash = 47

endOfLine w = w == 13 || w == 10

parseUntilBar =
  do x <- takeTill foundBar
     word8 bar
     return x

parseNumUntilBar =
  do num <- A.decimal
     word8 bar
     return num

parseInode = try parseInodeNorm <|> parseInodeFail

parseInodeFail =
  do x <- parseUntilBar
     return $ EmptyInode x

parseInodeNorm =
  do entryNum_ <- A.decimal
     word8 hyphen
     dataAttr_ <- A.decimal
     word8 hyphen
     dataSub_ <- A.decimal
     word8 bar
     return $ Inode entryNum_ dataAttr_ dataSub_

parsefileType =
  do fnStruct_ <- A.anyChar
     word8 slash
     metaStruct_ <- A.anyChar
     return $ FT fnStruct_ metaStruct_

parsePerms =
  do read_ <- A.anyChar
     write_ <- A.anyChar
     exec_ <- A.anyChar
     return $ P (read_ == 'r') (write_ == 'w') (exec_ == 'x')

parseFilePerms =
  do owner_ <- parsePerms
     group_ <- parsePerms
     other_ <- parsePerms
     word8 bar
     return $ FP owner_ group_ other_

bLine =
  do md5_ <- parseNumUntilBar
     fn_ <- parseUntilBar
     inode_ <- parseInode
     fileType_ <- parsefileType
     filePerms_ <- parseFilePerms
     uid_ <- parseNumUntilBar
     gid_ <- parseNumUntilBar
     size_ <- parseNumUntilBar
     atime_ <- parseNumUntilBar
     mtime_ <- parseNumUntilBar
     ctime_ <- parseNumUntilBar
     crtime_ <- A.decimal
     skipWhile endOfLine
     return $ BL md5_ fn_ inode_ fileType_ filePerms_ uid_ gid_ size_ atime_ mtime_ ctime_ crtime_

event =
  do md5_ <- parseNumUntilBar
     fn_ <- parseUntilBar
     inode_ <- parseInode
     fileType_ <- parsefileType
     filePerms_ <- parseFilePerms
     uid_ <- parseNumUntilBar
     gid_ <- parseNumUntilBar
     size_ <- parseNumUntilBar
     atime_ <- parseNumUntilBar
     mtime_ <- parseNumUntilBar
     ctime_ <- parseNumUntilBar
     crtime_ <- A.decimal
     skipWhile endOfLine
     return $ E fn_ atime_ mtime_ ctime_ crtime_

bLines = many1 bLine
events = many1 event

parseBFile input = parse bLines input
maybeParseB input = maybeResult (parseBFile input)

parseEvents input = parse events input
maybeParseE input = maybeResult (parseEvents input)
